package com.xinghanlaser.applet.base.common.handler;

import cn.hutool.core.lang.UUID;
import cn.hutool.core.util.ObjectUtil;
import com.xinghanlaser.applet.base.common.entity.ResponseEntity;
import com.xinghanlaser.applet.base.common.exception.BizException;
import com.xinghanlaser.applet.base.common.exception.ServiceException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import javax.servlet.http.HttpServletRequest;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.io.IOException;
import java.security.InvalidParameterException;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * <p>
 *  全局异常捕捉
 * <p>
 *
 * @author: mftuo
 * @since: 2024/2/28 15:34
 */
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {
    @ExceptionHandler(BizException.class)
    public ResponseEntity<Void> handleBizException(BizException bizException, HttpServletRequest request){
        String uuid = logParamsFromRequest(request, bizException.getMessage());
        log.error("【{}】业务异常:{}",uuid, bizException.getMessage());

        return ResponseEntity.faultMsg(bizException.getMessage());
    }

    @ExceptionHandler(InvalidParameterException.class)
    public ResponseEntity<Void> handleInvalidParameterException(InvalidParameterException e, HttpServletRequest request) {
        String uuid = logParamsFromRequest(request, e.getMessage());
        log.error("【{}】参数校验异常:{}", uuid,e.getMessage());

        return ResponseEntity.faultMsg(e.getMessage());
    }

    @ExceptionHandler(BindException.class)
    public ResponseEntity<Void> validationBindException(BindException e, HttpServletRequest request) {

        List<FieldError> fieldErrors = e.getBindingResult().getFieldErrors();
        String message = fieldErrors.stream()
                .map(FieldError::getDefaultMessage)
                .collect(Collectors.joining(" && "));

        String uuid = logParamsFromRequest(request, message);
        log.error("【{}】参数错误: {}",uuid, message, e);
        return ResponseEntity.faultMsg(message);
    }

    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ResponseEntity<Void> validationMethodArgumentNotValidException(MethodArgumentNotValidException e, HttpServletRequest request) {
        List<FieldError> fieldErrors = e.getBindingResult().getFieldErrors();
        String message = fieldErrors.stream()
                .map(FieldError::getDefaultMessage)
                .collect(Collectors.joining(" && "));

        String uuid = logParamsFromRequest(request, message);
        log.error("【{}】参数错误: {}", uuid,message);

        return ResponseEntity.faultMsg(message);
    }

    @ExceptionHandler(ConstraintViolationException.class)
    public ResponseEntity<Void> validationConstraintViolationException(ConstraintViolationException e, HttpServletRequest request) {
        Set<ConstraintViolation<?>> constraintViolationSet = e.getConstraintViolations();
        String message = constraintViolationSet.stream()
                .map(ConstraintViolation::getMessage)
                .collect(Collectors.joining(" && "));

        String uuid = logParamsFromRequest(request, message);
        log.error("【{}】参数错误: {}",uuid, message);

        return ResponseEntity.faultMsg(message);
    }

    @ExceptionHandler(Exception.class)
    public ResponseEntity<Void> handleBizException(Exception e, HttpServletRequest request) {
        String uuid = logParamsFromRequest(request, e.getMessage());
        log.error("【{}】异常:{}",uuid, e.getMessage(), e);

        return ResponseEntity.faultMsg("系统异常");
    }

    @ExceptionHandler(ServiceException.class)
    public ResponseEntity<Void> handleServiceException(ServiceException e, HttpServletRequest request) {
        String uuid = logParamsFromRequest(request, e.getMessage());
        log.error("【{}】服务异常接口:{}",uuid, e.getMessage(), e);

        return e.response();
    }

    private String logParamsFromRequest(HttpServletRequest request, String msg){
        if(ObjectUtil.isNull(request)) return null;

        final String url = request.getRequestURL().toString();
        final String method = request.getMethod();

        final String uuid = UUID.randomUUID().toString();
        log.error("【{}】【=== 请求异常日志 开始 ====】", uuid);
        log.error("【{}】【请求URL】: {}", uuid, url);
        log.error("【{}】【请求方法】: {}", uuid, method);
        log.error("【{}】【请求参数】: {}", uuid, request.getQueryString());
        log.error("【{}】【异常信息】: {}", uuid, msg);
        String SEPARATOR = System.lineSeparator();

        if("GET".equals(method)) {
            log.error("【{}】【=== 请求异常日志 结束 ====】{}", uuid, SEPARATOR);
            return uuid;
        }

        try {
            MultiReadHttpServletRequest multiReadRequest = null;
            multiReadRequest = new MultiReadHttpServletRequest(request);
            String requestBody = multiReadRequest.getRequestBodyAsString();
            log.error("【{}】【请求体】: {}", uuid, requestBody);
        } catch (IOException e) {
            log.error("解析请求体异常");
        }

        log.error("【{}】【=== 请求异常日志 结束 ====】{}", uuid, SEPARATOR);
        return uuid;
    }

}
